home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / Samples / Moofwars 1.02 / MoofWars Sprocket / •Source / TTileCollection.cp < prev    next >
Encoding:
Text File  |  1998-08-10  |  35.4 KB  |  1,091 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. TTileCollection.cp
  3.  
  4. A TileCollection is a set of tiles that can be used to draw a grid.  Essentially, 
  5. this class performs the same function that the TGraphicCollection class does, but 
  6. it is designed just to draw 32x32x8 tiles.  By making this code as specific as
  7. possible, this code is more than twice as fast as using TGraphics to draw the tiles.
  8.  
  9. Author: Timothy Carroll
  10. Apple Developer Technical Support
  11. timc@apple.com
  12.  
  13. Modification History: 
  14.  
  15. 1/23/97     TMC        Added include for Moofwars.h so that MrC will compile
  16. 8/15/96        TMC     Initial Release
  17.  
  18. Copyright © 1996, 1997 Apple Computer, Inc., All Rights Reserved
  19.  
  20. You may incorporate this sample code into your applications without
  21. restriction, though the sample code has been provided "AS IS" and the
  22. responsibility for its operation is 100% yours.  However, what you are
  23. not permitted to do is to redistribute the source as "DSC Sample Code"
  24. after having made changes. If you're going to re-distribute the source,
  25. we require that you make it clear in the source that the code was
  26. descended from Apple Sample Code, but that you've made changes.
  27. *************************************************************************************/
  28.  
  29. #include <Memory.h>
  30. #include <Resources.h>
  31.  
  32.  
  33. #include "Moofwars.h"
  34. #include "TTileCollection.h"
  35. #include "Scaling.h"
  36.  
  37. #include "GridTilesFormat.h"
  38.  
  39.  
  40. const int kTileSize = 1024;
  41. const int kTileGroupSize = (kTileSize+1)*8;
  42.  
  43. /*************************************************************************************
  44.  
  45. Internal Declarations
  46.  
  47. We will hold the list of created TTileCollection objects in a handle.  This handle is 
  48. automatically created the first time we load a TTileCollection and is deallocated when
  49. the list is empty.
  50.  
  51. All of the allocation and deallocation is handled by the static NewCollection call.
  52.  
  53. NewCollection has a few utility routines it calls on to manage the handle.  Mainly they do
  54. the searching, insertion and deletion from the list.
  55. *************************************************************************************/
  56.  
  57. static Handle gTileCollectionList = NULL;
  58. static unsigned long gNumberItemsInList = 0;
  59.  
  60.  
  61.  
  62. static OSErr InsertCollectionIntoList (TTileCollection *theCollection, UInt32 index);
  63. static OSErr DeleteCollectionFromList (UInt32 index);
  64. static OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index);
  65.  
  66. /*************************************************************************************
  67.     InsertCollectionIntoList
  68.     
  69.     This routine creates the handle if necessary, and otherwise inserts the TTileCollection
  70.     into the list at the index location given.
  71.     
  72.     Assumptions:
  73.         theCollection must be a legitimate TTileCollection -- no NULL parameters.
  74.         index must be no more than 1 larger than gNumberItemsInList. ?????
  75. *************************************************************************************/
  76.  
  77. OSErr InsertCollectionIntoList (TTileCollection *theCollection, UInt32 index)
  78. {
  79.     OSErr theErr = noErr;
  80.  
  81. #if qDebugging
  82.     if (index > gNumberItemsInList)
  83.         SIGNAL_ERROR ("\pAttempting to insert collection at invalid index")
  84.     if (theCollection == NULL)
  85.         SIGNAL_ERROR ("\pAttempting to insert a null collection into the list")    
  86.     
  87. #endif
  88.     
  89.     if (gTileCollectionList == NULL)
  90.     {
  91.         gNumberItemsInList = 1;
  92.         
  93.         gTileCollectionList = NewHandleClear (sizeof (TTileCollection *));
  94.         theErr = MemError();
  95.         
  96.         FAIL_OSERR (theErr, "\pCouldn't allocate a new handle of information")
  97.         FAIL_NIL (gTileCollectionList, "\pCouldn't allocate a new handle of information")
  98.         
  99.     }
  100.     else
  101.     {
  102.         gNumberItemsInList++;
  103.         SetHandleSize(gTileCollectionList,gNumberItemsInList*sizeof(TTileCollection *));
  104.         
  105.         theErr = MemError();
  106.         FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
  107.         FAIL_NIL (gTileCollectionList, "\pCouldn't resize the list handle")
  108.         
  109.         // Shift the data to make room
  110.         BlockMoveData(    (*(TTileCollection ***)gTileCollectionList)+index,
  111.                         (*(TTileCollection ***)gTileCollectionList)+index+1,
  112.                         (gNumberItemsInList - index-1) * sizeof(TTileCollection *));
  113.     }
  114.     
  115.     // finally, set the new object in place
  116.             *((*(TTileCollection ***) gTileCollectionList)+index) = theCollection;
  117.  
  118.     return noErr;
  119.     
  120.     error:
  121.     
  122.     
  123.     if (theErr == noErr)
  124.         theErr = paramErr;
  125.     return theErr;
  126. }
  127.  
  128.  
  129. /*************************************************************************************
  130.     DeleteCollectionFromList
  131.     
  132.     This routine removes the collection from the list and destroys it.  If there are no more items
  133.     in the list then we dispose of the handle.
  134.     
  135.     Assumptions:
  136.     index must be within the list.
  137. *************************************************************************************/
  138. OSErr DeleteCollectionFromList (UInt32 index)
  139. {
  140.     OSErr theErr;
  141.     
  142.     gNumberItemsInList--;
  143.     
  144.     //    slide remaining elements up
  145.     
  146.     BlockMoveData(    (*(TTileCollection ***)gTileCollectionList)+index+1,
  147.                     (*(TTileCollection ***)gTileCollectionList)+index,
  148.                     (gNumberItemsInList - index) * sizeof(TTileCollection *));
  149.  
  150.     //    cut back the storage and dispose of the handle if we have no items left
  151.     
  152.     
  153.     if (gNumberItemsInList> 0)
  154.     {
  155.         SetHandleSize((Handle) gTileCollectionList,gNumberItemsInList*sizeof(TTileCollection *));
  156.         theErr = MemError();
  157.         FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
  158.         FAIL_NIL (gTileCollectionList, "\pCouldn't resize the list handle")
  159.     }
  160.     
  161.     else
  162.     {
  163.         DisposeHandle (gTileCollectionList);
  164.         gTileCollectionList = NULL;
  165.     }
  166.     
  167.     
  168.     return noErr;
  169.     error:
  170.     
  171.     
  172.     if (theErr == noErr)
  173.         theErr = paramErr;
  174.     return theErr;
  175. }
  176.  
  177.  
  178. /*************************************************************************************
  179.     SearchCollectionList
  180.     
  181.     This routine searches through the list and attempts to find an existing TTileCollection with
  182.     that resID.  If it finds one with that resID, then it returns the index to that collection and
  183.     sets found to true.  If it doesn't find that resource, then it sets found to false AND sets the
  184.     index to where it should be inserted into the list.
  185. *************************************************************************************/
  186. OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index)
  187. {    
  188.     UInt32 low = 0;
  189.     UInt32 high = gNumberItemsInList;
  190.     UInt32 tempIndex;
  191.     TTileCollection *theItem;
  192.     
  193.     OSErr theErr = noErr;
  194.     
  195.     *found = false;
  196.     
  197.     while (low < high)
  198.         {
  199.         tempIndex = (low+high) >> 1;
  200.         
  201.         theItem = (*(TTileCollection ***)gTileCollectionList)[tempIndex];
  202.         
  203.         FAIL_NIL (theItem, "\pBad TTile object")
  204.         
  205.         if (resID < theItem->GetResID())
  206.             high = tempIndex;                    //    element is below "high"
  207.         else if (resID == theItem->GetResID())
  208.             {
  209.             *found = true;
  210.             *index = tempIndex;
  211.             return noErr;
  212.             }
  213.         else
  214.             low = tempIndex+1;                    //    element is above "low"
  215.         }
  216.     
  217.     // use final calculations to put insert in the right place in the list
  218.     *index = (low+high) >> 1;
  219.     return noErr;
  220.     
  221.     error:
  222.     
  223.     if (theErr == noErr)
  224.         theErr = paramErr;
  225.     return theErr;
  226.  
  227.  
  228. }
  229. /*************************************************************************************
  230.     TTileCollection::NewCollection
  231.     
  232.     This routine merely uses the routines we created above to properly create and load
  233.     the TTileCollections.
  234. *************************************************************************************/
  235. TTileCollection
  236. *TTileCollection::NewCollection (SInt16 resID)
  237. {
  238.     unsigned long        listIndex;
  239.     Boolean             tableAlreadyExists;
  240.     TTileCollection    *newCollection = NULL;
  241.     OSErr                theErr;
  242.     
  243.     theErr = SearchCollectionList (resID, &tableAlreadyExists, &listIndex);
  244.     FAIL_OSERR(theErr,"\pCouldn't search the collection list in TTileCollection::NewCollection")
  245.     
  246.     if (tableAlreadyExists)
  247.     {
  248.         // find the existing collection and add 1 to the ref count.
  249.         newCollection = (*(TTileCollection ***)gTileCollectionList)[listIndex];
  250.         newCollection->AddReference();
  251.     }
  252.     else
  253.     {
  254.         // create a new collection
  255.         newCollection = new TTileCollection(resID);
  256.         theErr = newCollection->CreateCollection ();
  257.         FAIL_OSERR(theErr,"\pCouldn't create new TTileCollection")
  258.         theErr = InsertCollectionIntoList(newCollection, listIndex);
  259.         FAIL_OSERR(theErr, "\pCouldn't add new TTileCollection to list")
  260.         newCollection->AddReference();
  261.     }
  262.     
  263.     return newCollection;
  264.     error:
  265.         if (newCollection != NULL)
  266.             delete newCollection;
  267.         return NULL;
  268. }
  269.  
  270.  
  271. /*************************************************************************************
  272.     TTileCollection::AddReference
  273. *************************************************************************************/
  274.  
  275. void
  276. TTileCollection::AddReference (void)
  277.    {
  278.        fReferenceCount++;
  279.    }
  280.    
  281.    
  282. /*************************************************************************************
  283.     TTileCollection::DisposeReference
  284. *************************************************************************************/
  285.  
  286. void 
  287. TTileCollection::DisposeReference (void)
  288. {
  289.        fReferenceCount--;
  290.        if (fReferenceCount == 0)
  291.        {
  292.            UInt32                listIndex;
  293.         Boolean             tableEntry;
  294.         OSErr                theErr;
  295.  
  296.         theErr = SearchCollectionList (fResID, &tableEntry, &listIndex);
  297.                 
  298.         FAIL_OSERR (theErr, "\pFailed to search the CollectionList")
  299.         FAIL_FALSE (tableEntry, "\pFailed to find an existing TTileCollection in list")
  300.                 
  301.         theErr = DeleteCollectionFromList(listIndex);
  302.         FAIL_OSERR (theErr, "\pFailed to delete Collection from the list")
  303.                 
  304.            delete this;
  305.        }
  306.            
  307.     error:
  308.        return;
  309. }
  310.    
  311.  
  312. /*************************************************************************************
  313.     TTileCollection::TTileCollection
  314.     
  315.     All of the actual work is done in CreateCollection
  316. *************************************************************************************/
  317.  
  318. TTileCollection::TTileCollection (SInt16 resID)
  319. {
  320.     fResID = resID;
  321.     fReferenceCount = 0;
  322.     fNumberOfTiles = 0;
  323.     fTiles = NULL;
  324. }
  325.  
  326.  
  327. /*************************************************************************************
  328.     TTileCollection::~TTileCollection
  329.     
  330.     All of the actual work is done in DeleteCollection
  331. *************************************************************************************/
  332.  
  333. TTileCollection::~TTileCollection (void)
  334. {
  335.     if (fTiles != NULL)
  336.         {
  337.         OSErr theErr = DestroyCollection();
  338.         FAIL_OSERR (theErr, "\pFailed to destroy the TTileCollection data")
  339.         }
  340.         
  341.     error:
  342.     return;
  343. }
  344.  
  345.  
  346. /*************************************************************************************
  347.     TTileCollection::CreateCollection
  348.     
  349.     This routine uses the resource number we passed into the contructor to load the TTileCollection
  350.     from the 'SptA' resource we created for it.  Note that we don't make any assumptions about
  351.     the resource file being used, so the correct resource file already needs to be opened for this
  352.     call to work.
  353. *************************************************************************************/
  354.  
  355. OSErr TTileCollection::CreateCollection(void)
  356. {
  357.     OSErr     theErr = noErr;
  358.     TileCollectionResHeader **tiles;
  359.     int        loop;
  360.     Ptr        srcPtr, destPtr;
  361.     
  362.     // Load the 'TILE' resource and check to make sure we can read the header information.
  363.     
  364.     tiles = (TileCollectionResHeader **) Get1Resource (TileCollectionResType, fResID);
  365.     theErr = ResError();
  366.     
  367.     FAIL_OSERR (theErr, "\pFailed to load the TILE resource.")
  368.     FAIL_NIL (tiles, "\pFailed to load the TILE resource.")
  369.  
  370.     if ( (**tiles).version != 0) SIGNAL_ERROR ("\pInvalid version number in TILE resource")
  371.     if ( (**tiles).depth != 8) SIGNAL_ERROR ("\pInvalid Pixel Depth in TILE resource")
  372.     fNumberOfTiles = (**tiles).numTiles;
  373.     
  374.     fTiles = NewHandle (fNumberOfTiles * kTileGroupSize);
  375.     theErr = MemError();
  376.     
  377.     FAIL_OSERR (theErr, "\pFailed to allocate memory for the tiles")
  378.     FAIL_NIL (fTiles, "\pFailed to allocate memory for the tiles")
  379.     
  380.     srcPtr = (Ptr)(*tiles) + sizeof (TileCollectionResHeader);
  381.     destPtr = (*fTiles);
  382.     
  383.     fTileOffset = (fNumberOfTiles * kTileSize) +1;
  384.     for (loop = 0; loop < 8; loop++)
  385.     {
  386.         BlockMoveData (srcPtr, destPtr, kTileSize*fNumberOfTiles);
  387.         destPtr += fTileOffset;
  388.     }
  389.     
  390.     // Completed successfully, cleanup and exit with no error;
  391.     goto cleanup;
  392.     
  393.     error:
  394.     if (theErr == noErr)
  395.         theErr = paramErr;
  396.     
  397.     if (fTiles != NULL)
  398.         DisposeHandle (fTiles);
  399.     fTiles = NULL;
  400.     
  401.     cleanup:
  402.     
  403.     if (tiles != NULL)
  404.         ReleaseResource ((Handle) tiles);        
  405.  
  406.     return theErr;
  407. }
  408.  
  409.  
  410. /*************************************************************************************
  411.     TTileCollection::DestroyCollection
  412.     
  413.     Throw away all of the objects that we're created.  We do check for null TTile objects here,
  414.     and properly skip null objects that might not have been finished from the create calls.
  415. *************************************************************************************/
  416.  
  417. OSErr
  418. TTileCollection::DestroyCollection (void)
  419. {
  420.     if (fTiles != NULL)
  421.         DisposeHandle (fTiles);
  422.     fTiles = NULL;
  423.     
  424.     return noErr;
  425. }
  426.  
  427.  
  428.  
  429. /*************************************************************************************
  430.     TTileCollection::LockCollection
  431.  
  432. *************************************************************************************/
  433.  
  434. OSErr
  435. TTileCollection::LockCollection (void)
  436. {
  437.     OSErr theErr = noErr;
  438.     
  439.     MoveHHi (fTiles);
  440.     theErr = MemError();
  441.     FAIL_OSERR (theErr, "\pCouldn't move fTiles handle high")
  442.     HLock (fTiles);
  443.     theErr = MemError();
  444.     FAIL_OSERR (theErr, "\pCouldn't lock fTiles handle")
  445.         
  446.     error:
  447.     return theErr;
  448. }
  449.  
  450.  
  451. /*************************************************************************************
  452.     TTileCollection::UnlockCollection
  453.  
  454. *************************************************************************************/
  455.  
  456. OSErr
  457. TTileCollection::UnlockCollection (void)
  458. {
  459.     OSErr theErr = noErr;
  460.     
  461.     HUnlock (fTiles);
  462.     theErr = MemError();
  463.     FAIL_OSERR (theErr, "\pCouldn't unlock fTiles handle")
  464.     
  465.     error:
  466.     return theErr;
  467. }
  468.                    
  469.  
  470. /*************************************************************************************
  471.     TTileCollection::CopyImageUnclipped
  472.     
  473.     This is a set of optimized image copying routines that take advantage of alignment for some serious
  474.     speed improvements.  These routines take the destination pointer and assume that the image being
  475.     copied is completely on the screen.  If your routine can't determine which of these routines to
  476.     call, call CopyImageClip instead.
  477.     
  478.     Now for a more detailed discussion of these routines and why we actually go about this.  The main
  479.     advantage to these routines is that their specialization allows them to be much faster than the
  480.     generic copying loop in the TGraphic class.
  481.     
  482.     The fastest way to move memory on PPC is usually to load and store float doubles, which are 64 bits
  483.     wide.  The problem is that if you decide to move doubles, you need to guarantee alignment to an
  484.     8 byte boundary, or your code will run slow on a 603 and 604 processor.  For the generic sprite
  485.     blitter, it was faster to just move longs and let the hardware deal with address misalignment.  But
  486.     for tiles, we can make copies of the same data at different alignments and use the correct data
  487.     when drawing to the screen.  In fact, we could do this for sprites too.  The main advantage is that
  488.     because we know the width of the tile, we can write a blitter loop that has no logic in it other
  489.     than loads and stores.  At one point, I did attempt to write a variable length blitter that did the
  490.     same thing, but for small sprites, the overhead of checking for the correct sprite was always more
  491.     than just drawing with longs.
  492.     
  493.     In any case, each of these blitters performs every load and every store on an exact boundary, with
  494.     no misalignments.  This results in much faster code in general, and also lets us load data into
  495.     the floats and stores.
  496.     
  497.     Future possibilities:
  498.     
  499.     * The cache touch instructions might be useful to make sure that the source data is loaded well ahead
  500.       of each time through the loop.  This can help performance, and is also possible to do for the
  501.       destination if the destination is cacheable.  I haven't experimented with this yet, but probably
  502.       will in the future.
  503.       
  504.     * Currently the largest number of loads for a single line is 7 (CopyImageUnclipped1).  Because the
  505.       next line starts immediately after the previous line in memory, we can probably replace 3 of the
  506.       loads (load char, load char, load short) with a single load long, and use shifts to get the correct
  507.       data.  This won't do much to reduce the number of stores, but might improve performance slightly.
  508.     
  509. *************************************************************************************/
  510.  
  511.  
  512. /***************************************
  513. TTileCollection::CopyImageUnclipped0
  514. ****************************************/
  515. void
  516. TTileCollection::CopyImageUnclipped0 (UInt32 index, unsigned char *destPtr)
  517. {
  518.     register double double1, double2, double3, double4;
  519.  
  520.     unsigned char    *srcPtr;        // the current position in the sprite data
  521.     int                loop;
  522.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  523.  
  524. #if qDebugging
  525.     if (gDestPixMap == NULL)
  526.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  527.                 
  528.     if  (index >= fNumberOfTiles)
  529.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  530.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  531. #endif
  532.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index);
  533.     rowBytesLocal = gRowBytes;
  534.  
  535.     for (loop = 0; loop < 32; loop++)
  536.     {
  537.         // load all the data into the registers
  538.  
  539.         double1 = *((double *) srcPtr);
  540.         double2 = *((double *) srcPtr+1);
  541.         double3 = *((double *) srcPtr+2);
  542.         double4 = *((double *) srcPtr+3);
  543.  
  544.         // dump all the data out to the destination.
  545.  
  546.         *((double *) destPtr)   = double1;
  547.         *((double *) destPtr+1) = double2;
  548.         *((double *) destPtr+2) = double3;
  549.         *((double *) destPtr+3) = double4;
  550.  
  551.         srcPtr += 32;
  552.         destPtr += rowBytesLocal;
  553.     }
  554.     
  555.     error:
  556.     return;
  557. }
  558.  
  559.  
  560.  
  561. /***************************************
  562. TTileCollection::CopyImageUnclipped1
  563. ****************************************/
  564. void
  565. TTileCollection::CopyImageUnclipped1 (UInt32 index, unsigned char *destPtr)
  566. {
  567.     register double double1, double2, double3;
  568.     register unsigned char  char1,char2;
  569.     register unsigned short short1;
  570.     register unsigned long  long1;
  571.  
  572.     unsigned char    *srcPtr;        // the current position in the sprite data
  573.     int                loop;
  574.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  575.  
  576. #if qDebugging
  577.     if (gDestPixMap == NULL)
  578.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  579.                 
  580.     if  (index >= fNumberOfTiles)
  581.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  582.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  583. #endif
  584.  
  585.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index + fTileOffset);
  586.     rowBytesLocal = gRowBytes;
  587.  
  588.     for (loop = 0; loop < 32; loop++)
  589.     {
  590.         // load all the data into the registers.  We're one byte misaligned, so we need to load 7 bytes before
  591.         // we hit the next 8-byte boundary.
  592.         
  593.         char1   = *((unsigned char *)                     srcPtr);
  594.         short1  = *((unsigned short *) ((unsigned char *) srcPtr+1));
  595.         long1   = *((unsigned long *)  ((unsigned char *) srcPtr+3));
  596.         double1 = *((double *)         ((unsigned char *) srcPtr+7));
  597.         double2 = *((double *)         ((unsigned char *) srcPtr+15));
  598.         double3 = *((double *)         ((unsigned char *) srcPtr+23));
  599.         char2   = *((unsigned char *)  ((unsigned char *) srcPtr+31));
  600.         
  601.         srcPtr += 32;
  602.         
  603.         // dump all the data out to the destination.
  604.         
  605.         *((unsigned char *)  ((unsigned char *) destPtr))    = char1;
  606.         *((unsigned short *) ((unsigned char *) destPtr+1))  = short1;
  607.         *((unsigned long *)  ((unsigned char *) destPtr+3))  = long1;
  608.         *((double *)          ((unsigned char *) destPtr+7))  = double1;
  609.         *((double *)         ((unsigned char *) destPtr+15)) = double2;
  610.         *((double *)         ((unsigned char *) destPtr+23)) = double3;
  611.         *((unsigned char *)  ((unsigned char *) destPtr+31)) = char2;
  612.         
  613.         destPtr += rowBytesLocal;
  614.     }
  615.  
  616.     error:
  617.     return;
  618. }
  619.  
  620.  
  621. /***************************************
  622. TTileCollection::CopyImageUnclipped2
  623. ****************************************/
  624. void
  625. TTileCollection::CopyImageUnclipped2 (UInt32 index, unsigned char *destPtr)
  626. {
  627.     register double double1, double2, double3;
  628.     register unsigned short short1, short2;
  629.     register unsigned long  long1;
  630.  
  631.     unsigned char    *srcPtr;        // the current position in the sprite data
  632.     int                loop;
  633.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  634.  
  635. #if qDebugging
  636.     if (gDestPixMap == NULL)
  637.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  638.                 
  639.     if  (index >= fNumberOfTiles)
  640.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  641.         SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  642. #endif
  643.  
  644.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index + fTileOffset*2);
  645.     rowBytesLocal = gRowBytes;
  646.  
  647.     for (loop = 0; loop < 32; loop++)
  648.     {
  649.  
  650.     // load all the data into the registers
  651.  
  652.         short1  = *((unsigned short *)                    srcPtr);
  653.         long1   = *((unsigned long *)  ((unsigned char *) srcPtr+2));
  654.         double1 = *((double *)         ((unsigned char *) srcPtr+6));
  655.         double2 = *((double *)         ((unsigned char *) srcPtr+14));
  656.         double3 = *((double *)         ((unsigned char *) srcPtr+22));
  657.         short2  = *((unsigned short *) ((unsigned char *) srcPtr+30));
  658.         
  659.         // dump all the data out to the destination.
  660.         *((unsigned short *)  ((unsigned char *) destPtr))    = short1;
  661.         *((unsigned long *)   ((unsigned char *) destPtr+2))  = long1;
  662.         *((double *)          ((unsigned char *) destPtr+6))  = double1;
  663.         *((double *)          ((unsigned char *) destPtr+14)) = double2;
  664.         *((double *)          ((unsigned char *) destPtr+22)) = double3;
  665.         *((unsigned short *)  ((unsigned char *) destPtr+30)) = short2;
  666.         
  667.         srcPtr += 32;
  668.         destPtr += rowBytesLocal;
  669.     }
  670.     
  671.     error:
  672.     return;
  673. }
  674.  
  675.  
  676.  
  677. /***************************************
  678. TTileCollection::CopyImageUnclipped3
  679. ****************************************/
  680. void 
  681. TTileCollection::CopyImageUnclipped3 (UInt32 index, unsigned char *destPtr)
  682. {
  683.     register double double1, double2, double3;
  684.     register unsigned char  char1,char2;
  685.     register unsigned short short1;
  686.     register unsigned long  long1;
  687.  
  688.     unsigned char    *srcPtr;        // the current position in the sprite data
  689.     int                loop;
  690.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  691.  
  692. #if qDebugging
  693.     if (gDestPixMap == NULL)
  694.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  695.                 
  696.     if  (index >= fNumberOfTiles)
  697.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  698.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  699. #endif
  700.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index + fTileOffset*3);
  701.     rowBytesLocal = gRowBytes;
  702.  
  703.     for (loop = 0; loop < 32; loop++)
  704.     {
  705.  
  706.         // load all the data into the registers
  707.         
  708.         char1   = *((unsigned char *)                    srcPtr);
  709.         long1   = *((unsigned long *)  ((unsigned char *)srcPtr+1));
  710.         double1 = *((double *)         ((unsigned char *)srcPtr+5));
  711.         double2 = *((double *)         ((unsigned char *)srcPtr+13));
  712.         double3 = *((double *)         ((unsigned char *)srcPtr+21));
  713.         char2   = *((unsigned char *)  ((unsigned char *)srcPtr+29));
  714.         short1  = *((unsigned short *) ((unsigned char *)srcPtr+30));
  715.         
  716.         // dump all the data out to the destination.
  717.         *((unsigned char *) ((unsigned char *) destPtr))    = char1;
  718.         *((unsigned long *) ((unsigned char *) destPtr+1))  = long1;
  719.         *((double *)        ((unsigned char *) destPtr+5))  = double1;
  720.         *((double *)        ((unsigned char *) destPtr+13)) = double2;
  721.         *((double *)        ((unsigned char *) destPtr+21)) = double3;
  722.         *((unsigned char *) ((unsigned char *) destPtr+29)) = char2;
  723.         *((unsigned short *)((unsigned char *) destPtr+30)) = short1;
  724.         
  725.         srcPtr += 32;
  726.         destPtr += rowBytesLocal;
  727.     }
  728.     
  729.     error:
  730.     return;
  731. }
  732.  
  733.  
  734.  
  735. /***************************************
  736. TTileCollection::CopyImageUnclipped4
  737. ****************************************/
  738. void
  739. TTileCollection::CopyImageUnclipped4 (UInt32 index, unsigned char *destPtr)
  740. {
  741.     register double double1, double2, double3;
  742.     register unsigned long  long1, long2;
  743.  
  744.     unsigned char    *srcPtr;        // the current position in the sprite data
  745.     int                loop;
  746.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  747.  
  748. #if qDebugging
  749.     if (gDestPixMap == NULL)
  750.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  751.                 
  752.     if  (index >= fNumberOfTiles)
  753.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  754.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  755. #endif
  756.     //srcPtr =  (unsigned char *)  ((*fTiles) + alignment * fTileOffset + kTileSize*index);
  757.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index + 4*fTileOffset);
  758.     rowBytesLocal = gRowBytes;
  759.  
  760.     for (loop = 0; loop < 32; loop++)
  761.     {
  762.         long1   = *((unsigned long *) ((unsigned char *)srcPtr));
  763.         double1 = *((double *)        ((unsigned char *)srcPtr+4));
  764.         double2 = *((double *)        ((unsigned char *)srcPtr+12));
  765.         double3 = *((double *)        ((unsigned char *)srcPtr+20));
  766.         long2   = *((unsigned long *) ((unsigned char *)srcPtr+28));
  767.         
  768.         // dump all the data out to the destination.
  769.         *((unsigned long *) ((unsigned char *) destPtr))    = long1;
  770.         *((double *)        ((unsigned char *) destPtr+4))  = double1;
  771.         *((double *)        ((unsigned char *) destPtr+12)) = double2;
  772.         *((double *)        ((unsigned char *) destPtr+20)) = double3;
  773.         *((unsigned long *) ((unsigned char *) destPtr+28)) = long2;
  774.         
  775.         srcPtr += 32;
  776.         destPtr += rowBytesLocal;
  777.     }
  778.  
  779.  
  780.     error:
  781.     return;
  782. }
  783.  
  784.  
  785.  
  786. /***************************************
  787. TTileCollection::CopyImageUnclipped5
  788. ****************************************/
  789. void
  790. TTileCollection::CopyImageUnclipped5 (UInt32 index, unsigned char *destPtr)
  791. {
  792.     register double double1, double2, double3;
  793.     register unsigned char  char1,char2;
  794.     register unsigned short short1;
  795.     register unsigned long  long1;
  796.  
  797.     unsigned char    *srcPtr;        // the current position in the sprite data
  798.     int                loop;
  799.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  800.  
  801. #if qDebugging
  802.     if (gDestPixMap == NULL)
  803.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  804.                 
  805.     if  (index >= fNumberOfTiles)
  806.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  807.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  808. #endif
  809.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index + 5*fTileOffset);
  810.     rowBytesLocal = gRowBytes;
  811.  
  812.     for (loop = 0; loop < 32; loop++)
  813.     {
  814.  
  815.                 // load all the data into the registers
  816.         char1   = *((unsigned char *)  ((unsigned char *) srcPtr+0));
  817.         short1  = *((unsigned short *) ((unsigned char *) srcPtr+1));
  818.         double1 = *((double *)         ((unsigned char *) srcPtr+3));
  819.         double2 = *((double *)         ((unsigned char *) srcPtr+11));
  820.         double3 = *((double *)         ((unsigned char *) srcPtr+19));
  821.         long1   = *((unsigned long *)  ((unsigned char *) srcPtr+27));
  822.         char2   = *((unsigned char *)  ((unsigned char *) srcPtr+31));
  823.  
  824.         *((unsigned char *) ((unsigned char *) destPtr+0))  = char1;
  825.         *((unsigned short *)((unsigned char *) destPtr+1))  = short1;
  826.         *((double *)        ((unsigned char *) destPtr+3))  = double1;
  827.         *((double *)        ((unsigned char *) destPtr+11)) = double2;
  828.         *((double *)        ((unsigned char *) destPtr+19)) = double3;
  829.         *((unsigned long *) ((unsigned char *) destPtr+27)) = long1;
  830.         *((unsigned char *) ((unsigned char *) destPtr+31)) = char2;
  831.     
  832.         srcPtr += 32;
  833.         destPtr += rowBytesLocal;
  834.     }
  835.  
  836.     error:
  837.     return;
  838. }
  839.  
  840. /***************************************
  841. TTileCollection::CopyImageUnclipped6
  842. ****************************************/
  843. void
  844. TTileCollection::CopyImageUnclipped6 (UInt32 index, unsigned char *destPtr)
  845. {
  846.     register double double1, double2, double3;
  847.     register unsigned short short1, short2;
  848.     register unsigned long  long1;
  849.  
  850.     unsigned char    *srcPtr;        // the current position in the sprite data
  851.     int                loop;
  852.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  853.  
  854. #if qDebugging
  855.     if (gDestPixMap == NULL)
  856.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  857.                 
  858.     if  (index >= fNumberOfTiles)
  859.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  860.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  861. #endif
  862.     //srcPtr =  (unsigned char *)  ((*fTiles) + alignment * fTileOffset + kTileSize*index);
  863.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index + 6*fTileOffset);
  864.     rowBytesLocal = gRowBytes;
  865.  
  866.     for (loop = 0; loop < 32; loop++)
  867.     {
  868.  
  869.         short1  = *((unsigned short *) ((unsigned char *) srcPtr+0));
  870.         double1 = *((double *)         ((unsigned char *) srcPtr+2));
  871.         double2 = *((double *)         ((unsigned char *) srcPtr+10));
  872.         double3 = *((double *)         ((unsigned char *) srcPtr+18));
  873.         long1   = *((unsigned long *)  ((unsigned char *) srcPtr+26));
  874.         short2  = *((unsigned short *) ((unsigned char *) srcPtr+30));
  875.         
  876.         *((unsigned short *)((unsigned char *) destPtr+0))  = short1;
  877.         *((double *)        ((unsigned char *) destPtr+2))  = double1;
  878.         *((double *)        ((unsigned char *) destPtr+10)) = double2;
  879.         *((double *)        ((unsigned char *) destPtr+18)) = double3;
  880.         *((unsigned long *) ((unsigned char *) destPtr+26)) = long1;
  881.         *((unsigned short *)((unsigned char *) destPtr+30))  = short2;
  882.         
  883.         srcPtr += 32;
  884.         destPtr += rowBytesLocal;
  885.     }
  886.  
  887.     error:
  888.     return;
  889. }
  890.  
  891.  
  892. /***************************************
  893. TTileCollection::CopyImageUnclipped7
  894. ****************************************/
  895. void
  896. TTileCollection::CopyImageUnclipped7 (UInt32 index, unsigned char *destPtr)
  897. {
  898.     register double double1, double2, double3;
  899.     register unsigned char  char1,char2;
  900.     register unsigned short short1;
  901.     register unsigned long  long1;
  902.  
  903.     unsigned char    *srcPtr;        // the current position in the sprite data
  904.     int                loop;
  905.     int                rowBytesLocal;  // used to hold the rowbytes value to eliminate a load.
  906.  
  907. #if qDebugging
  908.     if (gDestPixMap == NULL)
  909.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  910.                 
  911.     if  (index >= fNumberOfTiles)
  912.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  913.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  914. #endif
  915.     //srcPtr =  (unsigned char *)  ((*fTiles) + alignment * fTileOffset + kTileSize*index);
  916.     srcPtr =  (unsigned char *)  ((*fTiles)  + kTileSize*index+ 7*fTileOffset);
  917.     rowBytesLocal = gRowBytes;
  918.  
  919.     for (loop = 0; loop < 32; loop++)
  920.     {
  921.  
  922.         char1   = *((unsigned char *)  ((unsigned char *) srcPtr+0));
  923.         double1 = *((double *)         ((unsigned char *) srcPtr+1));
  924.         double2 = *((double *)         ((unsigned char *) srcPtr+9));
  925.         double3 = *((double *)         ((unsigned char *) srcPtr+17));
  926.         long1   = *((unsigned long *)  ((unsigned char *) srcPtr+25));
  927.         short1  = *((unsigned short *) ((unsigned char *) srcPtr+29));
  928.         char2   = *((unsigned char *)  ((unsigned char *) srcPtr+31));
  929.             
  930.         *((unsigned char *) ((unsigned char *) destPtr+0))  = char1;
  931.         *((double *)        ((unsigned char *) destPtr+1))  = double1;
  932.         *((double *)        ((unsigned char *) destPtr+9))  = double2;
  933.         *((double *)        ((unsigned char *) destPtr+17)) = double3;
  934.         *((unsigned long *) ((unsigned char *) destPtr+25)) = long1;
  935.         *((unsigned short *)((unsigned char *) destPtr+29)) = short1;
  936.         *((unsigned char *) ((unsigned char *) destPtr+31)) = char2;
  937.  
  938.         srcPtr += 32;
  939.         destPtr += rowBytesLocal;
  940.     }
  941.  
  942.     error:
  943.     return;
  944. }
  945.  
  946.  
  947. /*************************************************************************************
  948.     TTileCollection::CopyImageClipped
  949.     
  950.     CopyImageClipped also draws the image, but always checks to make sure that it is inside the
  951.     designated drawing area set in the clipping rectangle for our drawing code.  For the moment, this
  952.     version of the code always does the drawing using simple long moves without regard to alignment.
  953.         
  954. *************************************************************************************/
  955.  
  956. void 
  957. TTileCollection::CopyImageClipped (UInt32 index, SInt32 top, SInt32 left)
  958. {
  959. #if qDebugging
  960.     if (gDestPixMap == NULL)
  961.         SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap")
  962.                 
  963.     if (EmptyRect (&gClipRect))
  964.         SIGNAL_ERROR ("\pEmpty Clipping Region")
  965.         
  966.     if  (index >= fNumberOfTiles)
  967.         // We're outside of the bounds of the Tiles table here.  Debugger time! :-)
  968.             SIGNAL_ERROR("\ptried to index a TTile that was out of bounds");
  969. #endif
  970.  
  971.     // We'll do all our calculations in variables rather than use a structure.
  972.     // hopefully this should speed things up
  973.     SInt32 destTop, destBottom, destLeft, destRight;
  974.     
  975.     destTop    = top;
  976.     destBottom = top+32;
  977.     destLeft   = left;
  978.     destRight  = left+32;
  979.     
  980.     // determine if the spite needs to be drawn at all
  981.     if    (destTop >= gClipRect.bottom || destBottom <= gClipRect.top ||
  982.          destLeft >= gClipRect.right || destRight <= gClipRect.left )
  983.         // no need to draw, goodbye
  984.         return;
  985.     
  986.     // determine if the sprite will be clipped
  987.     if     (destTop < gClipRect.top || destBottom > gClipRect.bottom ||
  988.          destLeft < gClipRect.left || destRight > gClipRect.right)
  989.     {
  990.         UInt32 clipTop, clipBottom, clipLeft, clipRight;
  991.         unsigned char    *srcPtr;                        // the current position in the tile data
  992.         unsigned char    *destPtr;                        // the current position in the destination pixmap
  993.         unsigned long   blitwidth, blitheight;
  994.         unsigned long    yLoop;
  995.         unsigned long    sourceOffset, destOffset;
  996.         
  997.         // Calculate clipping rectangle.
  998.         clipTop    = destTop < gClipRect.top       ? gClipRect.top - destTop  : 0;
  999.         clipBottom = destBottom > gClipRect.bottom ? gClipRect.bottom-destTop : destBottom-destTop;
  1000.         clipLeft   = destLeft < gClipRect.left     ? gClipRect.left-destLeft  : 0;
  1001.         clipRight  = destRight > gClipRect.right   ? gClipRect.right-destLeft : destRight-destLeft;
  1002.  
  1003.         // calculate source and destination pointers
  1004.         srcPtr =  ( unsigned char * )( *fTiles ) + kTileSize*index;
  1005.         srcPtr += 32*clipTop+clipLeft;
  1006.         
  1007.         destPtr = gDestBaseAddr + (top + clipTop) * gRowBytes + left + clipLeft;
  1008.         
  1009.         // how much do we actually need to draw?
  1010.         blitwidth = clipRight - clipLeft;
  1011.         blitheight = clipBottom - clipTop;
  1012.         sourceOffset = 32-blitwidth;
  1013.         destOffset = gRowBytes-blitwidth;
  1014.         
  1015.         for (yLoop = 0; yLoop < blitheight; yLoop++)
  1016.         {
  1017.             register unsigned long sixteenblits, blitloop;
  1018.             sixteenblits = blitwidth >> 4;
  1019.             for ( blitloop = 0; blitloop < sixteenblits; blitloop++)
  1020.             {
  1021.                 register unsigned long temp1, temp2, temp3, temp4;
  1022.                 temp1 = ((unsigned long *) srcPtr)[0];
  1023.                 temp2 = ((unsigned long *) srcPtr)[1];
  1024.                 temp3 = ((unsigned long *) srcPtr)[2];
  1025.                 temp4 = ((unsigned long *) srcPtr)[3];
  1026.                 ((unsigned long *) destPtr)[0] = temp1;
  1027.                 ((unsigned long *) destPtr)[1] = temp2;
  1028.                 ((unsigned long *) destPtr)[2] = temp3;
  1029.                 ((unsigned long *) destPtr)[3] = temp4;
  1030.                 srcPtr += 16;
  1031.                 destPtr += 16;
  1032.             }
  1033.             // move any remaining data, up to 15 bytes total
  1034.             if (blitwidth & 0x8)
  1035.             {
  1036.                 register unsigned long temp1, temp2;
  1037.                 temp1 = ((unsigned long *) srcPtr)[0];
  1038.                 temp2 = ((unsigned long *) srcPtr)[1];
  1039.                 ((unsigned long *) destPtr)[0] = temp1;
  1040.                 ((unsigned long *) destPtr)[1] = temp2;
  1041.                 srcPtr += 8;
  1042.                 destPtr += 8;
  1043.             }
  1044.             if (blitwidth & 0x4)
  1045.             {
  1046.                 register unsigned long temp1;
  1047.                 temp1 = *((unsigned long *) srcPtr);
  1048.                 srcPtr +=4;
  1049.                 *((unsigned long *) destPtr)  = temp1;
  1050.                 destPtr +=4;
  1051.             }
  1052.             if (blitwidth & 0x2)
  1053.             {
  1054.                 register unsigned short temp1;
  1055.                 temp1 = *((unsigned short *) srcPtr);
  1056.                 srcPtr +=2;
  1057.                 *((unsigned short *) destPtr)  = temp1;
  1058.                 destPtr +=2;
  1059.             }
  1060.             if (blitwidth & 0x1)
  1061.                 *destPtr++ = *srcPtr++;
  1062.         srcPtr += sourceOffset;
  1063.         destPtr += destOffset;    
  1064.         }
  1065.  
  1066.     }
  1067.     else
  1068.     {
  1069.         // Unclipped, so calculate the destination pointer and alignment and call the appropriate unclipped case.
  1070.         unsigned char    *destPtr;                        // the current position in the destination pixmap
  1071.         long            alignment;
  1072.         
  1073.         
  1074.         destPtr = gDestBaseAddr + top * gRowBytes + left;
  1075.         alignment = ((long) destPtr) & 0x07;
  1076.         switch (alignment)
  1077.         {
  1078.             case 0: CopyImageUnclipped0 (index, destPtr); break;
  1079.             case 1: CopyImageUnclipped1 (index, destPtr); break;
  1080.             case 2: CopyImageUnclipped2 (index, destPtr); break;
  1081.             case 3: CopyImageUnclipped3 (index, destPtr); break;
  1082.             case 4: CopyImageUnclipped4 (index, destPtr); break;
  1083.             case 5: CopyImageUnclipped5 (index, destPtr); break;
  1084.             case 6: CopyImageUnclipped6 (index, destPtr); break;
  1085.             case 7: CopyImageUnclipped7 (index, destPtr); break;
  1086.         }
  1087.     }
  1088.  
  1089. error:
  1090.     return;
  1091. }